/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hxg.portmgr.core.device;

import hxg.portmgr.core.device.intf.IntfType;
import hxg.portmgr.core.device.intf.Intf;
import hxg.portmgr.core.find.Index;
import hxg.portmgr.core.find.MatchLevel;
import hxg.portmgr.core.ip.IpAddress;
import hxg.portmgr.core.ip.IpAddressEntry;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import hxg.portmgr.core.dao.DaoSource;
import hxg.portmgr.core.oper.Oper;
import hxg.portmgr.core.oper.OperType;
import hxg.portmgr.core.oper.snmp.SnmpOper;
import java.lang.reflect.InvocationTargetException;
import util.MapAdapter;

/**
 *
 * @author hxg
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {})
@XmlRootElement(name = "Device")
public class Device implements Comparable<Device> {

    private static final Logger logger = Logger.getLogger(Device.class.getName());
    @XmlAttribute
    @Index(name = "id", chsName = "id", level = MatchLevel.FullMatch)
    long id;
    @Index(name = "ip", chsName = "ip", level = MatchLevel.ContainMatch)
    @Attr(chsName = "ip", importAble = false, exportAble = true)
    @XmlAttribute
    String ip; //一般可用LOOP BACK IP,也不一定要有
    @XmlAttribute
    String snmpIp; //一些的设备配置引起的奇异问题,必要时可以自己指定用户SNMP操作的IP；
    //String sysOid; //用于判定设备型号的SNMP sysObjectId;
    @Index(name = "name", chsName = "设备名称", level = MatchLevel.ContainMatch)
    @Attr(chsName = "设备名称", importAble = false, exportAble = true)
    @XmlElement
    String name = "";  //设备的名称 ,对应SNMP 的sysName
    @Index(name = "desc", chsName = "设备描叙", level = MatchLevel.ContainMatch)
    @Attr(chsName = "设备描叙", importAble = false, exportAble = true)
    @XmlElement
    String desc; //设备的描叙,对应SNMP 的sysDes
    @Index(name = "chsname", chsName = "自定义名称", level = MatchLevel.PinYinBlurMatch)
    @Attr(chsName = "自定义名称", importAble = true, exportAble = true)
    @XmlAttribute
    String chsName; //自定义的中文名
    //@Index(name = "ips", chsName = "IP列表", level = MatchLevel.ContainMatch)
    @XmlElements({
        @XmlElement(name = "IpAddressEntry", type = IpAddressEntry.class)
    })
    IpAddressEntry[] ips;//注意IP列表中是有私网IP地址的，使用时要注意区分
    @XmlElement
    String sysOid;
    DeviceState state = DeviceState.OffLine;
    @XmlElement
    String SnmpReadCommunity = null;
    @XmlElement
    String SnmpWriteCommunity = null;
    @XmlElement
    @Attr(chsName = "序号偏移", importAble = true, exportAble = true)
    int offsideSequence;
    @XmlElement
    @XmlJavaTypeAdapter(MapAdapter.class)
    ConcurrentHashMap<String, String> AttrMap = new ConcurrentHashMap();
    //@XmlTransient
    //IntfDAO intfDao = DaoSource.getIntfDAO(this);

    public String getSnmpReadCommunity() {
        if (SnmpReadCommunity == null || SnmpReadCommunity.isEmpty()) {
            return "public";
        }
        return SnmpReadCommunity;
    }

    public void setSnmpReadCommunity(String SnmpReadCommunity) {
        this.SnmpReadCommunity = SnmpReadCommunity;
    }

    public String getSnmpWriteCommunity() {
        if (SnmpReadCommunity == null || SnmpReadCommunity.isEmpty()) {
            return "private";
        }
        return SnmpWriteCommunity;
    }

    public void setSnmpWriteCommunity(String SnmpWriteCommunity) {
        this.SnmpWriteCommunity = SnmpWriteCommunity;
    }

    // <editor-fold defaultstate="collapsed" desc="Default Getter and Setter">
    //@Index(name = "desc", chsName = "设备描叙", allowBlur = true, allowPinYin = false)
    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    //@Index(name = "ip", chsName = "设备主IP", allowBlur = true, allowPinYin = false)
    public String getIp() {
        return ip;
    }

    public synchronized void setIp(String ip) {
        this.ip = ip;
    }

    public String getSnmpIp() {
        return snmpIp;
    }

    public void setSnmpIp(String snmpIp) {
        this.snmpIp = snmpIp;
    }

    // @Index(name = "ips", chsName = "IP列表", allowBlur = true, allowPinYin = false)
    public IpAddressEntry[] getIps() {
        if (ips == null) {
            return new IpAddressEntry[]{new IpAddressEntry(ip, 32)};
        }
        return ips;
    }

    public synchronized void setIps(IpAddressEntry[] ips) {
        this.ips = ips;
    }

    public DeviceModel getModel() {
        return DaoSource.getDeviceModelDAO().getModelBySysOid(sysOid);
        //return model;
    }

    public void setModel(DeviceModel model) {
        sysOid = model.getSysOid();
    }

    // @Index(name = "name", chsName = "设备名称", allowBlur = false, allowPinYin = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (name != null) {
            this.name = name;
        }
    }

    //@Index(name = "chsname", chsName = "自定义名称", level = MatchLevel.PinYinBlurMatch)
    public String getChsName() {
        return chsName;
    }

    public void setChsName(String chsName) {
        this.chsName = chsName;
    }

    public DeviceType getType() {
        return getModel().getType();
    }

    @Deprecated
    public DeviceState getState() {
        return state;
    }

    @Deprecated
    public void setState(DeviceState state) {
        this.state = state;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getSysOid() {
        return sysOid;
    }

    public void setSysOid(String sysOid) {
        this.sysOid = sysOid;
    }

    public int getOffsideSequence() {
        return offsideSequence;
    }

    public void setOffsideSequence(int offsideSequence) {
        this.offsideSequence = offsideSequence;
    }

    //</editor-fold>
    public IntfType getdefaultIntfType() {
        return IntfType.EthPortIntf;
    }

    public Intf[] getIntfs() {
        return DaoSource.getIntfDAO().getIntfs(this);
    }

    public Intf getIntf(String ifidx) {
        for (Intf inf : getIntfs()) {
            if (inf.getIndex().equals(ifidx.trim())) {
                return inf;
            }
        }
        return null;
    }

    public Intf getIntf(IntfType type, int seq) {
        for (Intf inf : getIntfs()) {
            if (type == inf.getType() && inf.getSeq() == seq) {
                return inf;
            }
        }
        return null;
    }

    public void rebuildSequence(IntfType inftype, int minSeq, int step) {
        int offside = getOffsideSequence();
        Intf[] infs = getIntfs();
        //List<Intf> intfs = getSnmpOper().getIntfsByType(infs, inftype);        
        for (Intf inf : infs) {
            if (inf.getType() == inftype) {
                offside++;
                inf.setSequence(offside);
            }
        }
        DaoSource.getIntfDAO().save(this, infs);
        //saveIntfs(infs);
    }

    /**
     *
     * @return 一个不可添加、删除元素的不可修改Map
     */
    public Map<String, String> getAttrMap() {
        LinkedHashMap<String, String> mp = new LinkedHashMap<String, String>();
        mp.putAll(AttrMap);
        Map<String, String> finalmp = Collections.unmodifiableMap(mp);
        return finalmp;
    }

    public void putAttr(String attr, String value) {
        AttrMap.put(attr, value);
    }

    public String getAttr(String attr) {
        if (getType().getParams().contains(attr)) {
            if (!AttrMap.containsKey(attr)) {
                AttrMap.put(attr, "");
            }
            return AttrMap.get(attr);
        }
        return "";
    }

    /**
     * 同步或添加属性的方法,如果没有就添加新属性,有就同步 由于每次同步都要读些文件，请每一次尽量批量进行
     *
     * @param mp
     */
    public void synAttr(LinkedHashMap<String, String> mp) {
        //LinkedHashMap<String, String> map = getAttrMap();
        AttrMap.putAll(mp);
    }

    /**
     * 移除属性 由于每次同步都要读些文件，请每一次尽量批量进行
     *
     * @param attr
     */
    public void removeAttr(Collection<String> attrs) {
        //LinkedHashMap<String, String> map = getAttrMap();
        for (String attr : attrs) {
            AttrMap.remove(attr);
        }
        //saveAtttrMap(map);
    }

    /**
     * 移除属性 由于每次同步都要读些文件，请每一次尽量批量进行
     *
     * @param attr
     */
    public void removeAttr(String[] attrs) {
        //LinkedHashMap<String, String> map = getAttrMap();
        for (String attr : attrs) {
            AttrMap.remove(attr);
        }
        //saveAtttrMap(map);
    }

    /**
     * 清楚该设备占用的资源
     */
    public Oper getOper(hxg.portmgr.core.oper.OperType type) {
        return getOper((snmpIp == null || snmpIp.isEmpty()) ? ip : snmpIp, OperType.SnmpOper);
    }

    public Oper getOper(String ip, hxg.portmgr.core.oper.OperType type) {
        Class<? extends Oper> operclass = getModel().getOperclass();
        String read = SnmpReadCommunity;
        String write = SnmpWriteCommunity;
        if (operclass != null) {
            try {
                Constructor<SnmpOper> con = (Constructor<SnmpOper>) operclass.getConstructor(String.class, String.class, String.class);
                SnmpOper oper = con.newInstance(ip, read, write);
                return oper;
            } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
                logger.log(Level.SEVERE, null, ex);
                return null;
            }
        } else {
            return getModel().getType().getDefaultSnmpOper(ip, read, write);
        }

        //SnmpOper oper = model.getSnmpOper(ip, SnmpReadCommunity, SnmpWriteCommunity);
        //return oper;
    }

    public void scanStateIcmp() {
        int onlineIpcount = 0;
        boolean flag = false;
        for (IpAddressEntry devip : ips) {
            if (IpAddress.isSiteLocalAddress(devip.getIp())) {
                onlineIpcount++;
            } else {
                if (IpAddress.isReachAble(devip.getIp(), 5000)) {
                    onlineIpcount++;
                    flag = true;
                }
            }
        }
        if (onlineIpcount >= ips.length) {
            state = DeviceState.Online;
        } else {
            if (flag) {
                state = DeviceState.PartOffline;
            } else {
                state = DeviceState.OffLine;
            }
        }
    }

    //<editor-fold defaultstate="collapsed" desc="静态方法 设备扫描">
    public void resetDefaultManagerIP() {
        ip = DefaultManagerIP();
    }

    /**
     * 默认管理IP,规则:掩码最大的非私网IP(如果有多个相同的,返回第一个),如果没有符合的,返回自身IP
     */
    public String DefaultManagerIP() {
        IpAddressEntry ipAddr = null;
        for (IpAddressEntry ipe : ips) {
            if (!IpAddress.isSiteLocalAddress(ipe.getIp())) {
                if (ipAddr == null || ipAddr.getNetMaskInt() < ipe.getNetMaskInt()) {
                    ipAddr = ipe;
                }
            }
        }
        if (ipAddr == null) {
            return getIp();
        } else {
            return ipAddr.getIp();
        }
    }

    //</editor-fold>
    @Override
    public String toString() {
        if (chsName == null || chsName.isEmpty()) {
            return name;
        }
        return chsName;
    }

    @Override
    public int compareTo(Device o) {
        if (this.chsName.equals(o.chsName)) {
            if (ip.equals(o.getIp())) {
                return (int) (id - o.getId());
            } else {
                return ip.compareTo(o.getIp());
            }
        } else {
            return this.chsName.compareTo(o.chsName);
        }
    }

    public void saveIntfs(Intf[] ifs) {
        DaoSource.getIntfDAO().save(this, ifs);
    }

    @Deprecated
    public void clearIntfs() {
        //intfDao.clearAllIntfs();
    }
}
